package com.dc.member.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dc.base.BaseApiService;
import com.dc.base.BaseResponse;
import com.dc.constant.Constants;
import com.dc.core.token.GenerateToken;
import com.dc.core.transaction.RedisDataSoureceTransaction;
import com.dc.core.utils.MD5Util;
import com.dc.member.input.dto.UserLoginInpDTO;
import com.dc.member.mapper.UserMapper;
import com.dc.member.mapper.UserTokenMapper;
import com.dc.member.mapper.entity.UserDO;
import com.dc.member.mapper.entity.UserTokenDo;
import com.dc.member.service.IMemberLoginService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: KEYD
 * @Date: 2019/12/28 15:30
 * @Desc: 用户登录接口的实现类
 */
@RestController
public class MemberLoginSerivceImpl extends BaseApiService<JSONObject> implements IMemberLoginService {

    @Autowired
    private UserMapper userMapper;   //用户表

    @Autowired
    private UserTokenMapper userTokenMapper;  //token 表

    @Autowired
    private GenerateToken generateToken;

    @Autowired
    private RedisDataSoureceTransaction redisDataSoureceTransaction;  //数据库事务控制

    @Override
    public BaseResponse<JSONObject> login(@RequestBody UserLoginInpDTO userLoginInpDTO) {
        //1、验证参数
        String mobile = userLoginInpDTO.getMobile();
        if (StringUtils.isEmpty(mobile)) {
            return setResultError("手机号码不能为空!");
        }
        String password = userLoginInpDTO.getPassword();
        if (StringUtils.isEmpty(password)) {
            return setResultError("密码不能为空!");
        }
        //判断登录类型
        String loginType = userLoginInpDTO.getLoginType();
        if (StringUtils.isEmpty(loginType)) {
            return setResultError("登陆类型不能为空!");
        }
        // 设备信息
        String deviceInfor = userLoginInpDTO.getDeviceInfor();
        if (StringUtils.isEmpty(deviceInfor)) {
            return setResultError("设备信息不能为空!");
        }
        //目的是限制范围
        if (!(loginType.equals(Constants.MEMBER_LOGIN_TYPE_ANDROID) || loginType.equals(Constants.MEMBER_LOGIN_TYPE_IOS)
                || loginType.equals(Constants.MEMBER_LOGIN_TYPE_PC))) {
            return setResultError("登陆类型出现错误!");
        }
        //2、对登录密码实现加密
        String newpassword = MD5Util.MD5(password);
        //3、使用手机号码+密码进行登录.查询数据库，判断用户是否存在
        UserDO userDO = userMapper.login(mobile, newpassword);
        if (userDO == null) {
            return setResultError("用户名称或密码错误");
        }
        //用户登录 Token Session的区别，Token是sessionID、
        //用户每一个端登陆成功之后，会生成一个token令牌，（临时且唯一），存放在redis中作为rediskey，value为userId
        TransactionStatus transactionStatus = null;
        JSONObject data = new JSONObject();
        try {
            //4、获取userId
            Long userId = userDO.getUserId();
            //根据userId + loginType 查询当前登录类型账号之前是否有登录过
            UserTokenDo userTokenDo = userTokenMapper.selectByUserIdAndLoginType(userId, loginType);

            transactionStatus = redisDataSoureceTransaction.begin();//开启事务
            //如果登录过，清除之前redis的token  ，以前登录过，直接清除
            if (userTokenDo != null) {
                String token = userTokenDo.getToken();
                //如果开启redis事务，删除的时候，方法会返回false，事务提交才会是true。不开启事务才是true，
                generateToken.removeToken(token);  //删除以前的redis中的token
                int updateTokenAvailability = userTokenMapper.updateTokenAvailability(token);//mysql，令牌不可用
                if (!toDaoResult(updateTokenAvailability)) {
                    return setResultError("系统错误");
                }
                //if (isremoveToken) {
                //    //把该token的状态改为1   1不可用 0 可用  //token 过期的情况，这边就是一个bug
                //    userTokenMapper.updateTokenAvailability(token);  //mysql，令牌不可用
                //    //假设下面存在问题，数据库事务回滚
                //}
            }
            //5、生成对应用户令牌存放在redis中
            String keyprefix = Constants.MEMBER_TOKEN_KEYPREFIX + loginType;
            String newToken = generateToken.createToken(keyprefix, userId + "");

            //插入新的token
            UserTokenDo userToken = new UserTokenDo();
            userToken.setUserId(userId);
            userToken.setLoginType(userLoginInpDTO.getLoginType());
            userToken.setToken(newToken);
            userToken.setDeviceInfor(deviceInfor);
            int insertUserToken = userTokenMapper.insertUserToken(userToken);
            if (!toDaoResult(insertUserToken)) { //判断一下 数据 是否插入成功
                try {
                    redisDataSoureceTransaction.rollback(transactionStatus);  //回滚事务
                    return setResultError("系统错误");
                } catch (Exception e) {
                    e.printStackTrace();
                    return setResultError("系统错误");
                }
            }
            data.put("token", newToken);
            redisDataSoureceTransaction.commit(transactionStatus);  //提交事务
        } catch (Exception e) {
            try {
                redisDataSoureceTransaction.rollback(transactionStatus);
                return setResultError("系统错误");
            } catch (Exception ee) {
                ee.printStackTrace();
                return setResultError("系统错误");
            }
        }
        return setResultSuccess(data);
    }
}
